package io.netty.example.http.websocketx.server;

import com.alibaba.fastjson.JSON;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.example.http.websocketx.common.entity.NettyMessage;
import io.netty.example.http.websocketx.common.entity.enums.DispatchType;
import io.netty.example.http.websocketx.common.util.ByteNumberConverter;
import io.netty.example.http.websocketx.common.util.ByteObjConvert;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Date;

/**
 * @Description
 * @Author fuguangli businessfgl@163.com
 * @Create date:    2017/9/26
 */
public class SocketMessageHandler extends SimpleChannelInboundHandler<ByteBuf> {
    private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private static final Logger logger = LoggerFactory.getLogger(SocketMessageHandler.class);

    /**
     * <strong>Please keep in mind that this method will be renamed to
     * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.</strong>
     * <p>
     * Is called for each message of type {@link }.
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *            belongs to
     * @param data the message to handle
     * @throws Exception is thrown if an error occurred
     */
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf data) throws Exception {

//        byte[] msg = new byte[data.readableBytes()];
//        data.getBytes(0,msg);
//        System.err.println("server msg length="+msg.length);
//        System.out.println(new String(msg,"utf-8"));
//        assert msg.length==125:"error";

//        Thread.sleep(1000);
//        logger.info(ctx.channel() + " say : " + msg);
//
//        ctx.channel().writeAndFlush("server recieved");
        //提取数据
//        byte[][] gt = ByteObjConvert.extractMsg(msg);
//        do {
//            String jsonstr = ByteObjConvert.parseMsg(msg);
////            int baolen = ByteObjConvert.parseMsgLength(msg);
//
//            NettyMessage message = JSON.parseObject(jsonstr, NettyMessage.class);
//
//            logger.info(ctx.channel() + " say : " + message);
//
//
//            if (message.getDispatchType().equals(DispatchType.BROADCAST.toString())) {
//                for (Channel c : channels) {
//
////                    c.writeAndFlush(gt[0]);//传输的是包头加包体
//                    c.writeAndFlush(data);//传输的是包头加包体
//                }
//            }
//
//            gt = ByteObjConvert.extractMsg(gt[1]);
//        } while (gt[1].length > 0);

        String jsonstr = data.toString(Charset.forName("utf-8"));

        NettyMessage message = JSON.parseObject(jsonstr, NettyMessage.class);
        logger.info(ctx.channel() + " say : " + message);
        if (message.getDispatchType().equals(DispatchType.BROADCAST.toString())) {
            for (Channel c : channels) {
                c.writeAndFlush(ByteObjConvert.wrapMsg(jsonstr));//传输的是包头加包体
            }
        }
    }


    /**
     * Calls {@link ChannelHandlerContext#fireChannelActive()} to forward
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        channels.add(ctx.channel());
        logger.info("-------------------------------NEW CONNECTION");
        logger.info("最大内存:" + (Runtime.getRuntime().maxMemory() / 1024 / 1024));
        logger.info("已分配内存:" + (Runtime.getRuntime().totalMemory() / 1024 / 1024));
        logger.info("已分配内存中的剩余空间: " + (Runtime.getRuntime().freeMemory() / 1024 / 1024));
        logger.info("最大可用内存: " + (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024);


        logger.info(new Date() + ctx.channel().id().toString() + " join");
        logger.info("join--current group size=" + channels.size());
    }

    /**
     * Calls {@link ChannelHandlerContext#fireChannelInactive()} to forward
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info(ctx.channel().id().toString() + " leave");
        channels.remove(ctx.channel());
        logger.info("remove--current group size=" + channels.size());
        ctx.close();
    }

    /**
     * Calls {@link ChannelHandlerContext#fireChannelReadComplete()} to forward
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /**
     * Calls {@link ChannelHandlerContext#fireExceptionCaught(Throwable)} to forward
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error(ctx.channel().toString());
        super.exceptionCaught(ctx, cause);
    }
}
